package com.sp.synchronized_;


/**
 * 编程模拟三个售票窗口售票100, 分别使用继承Thread和实现Runnable方式, 并分析有什么问题
 * 会出现超卖现象, 票已经卖完了还在卖
 */
public class SellTicket {
    public static void main(String[] args) {

//        SellTicket03 sellTicket03 = new SellTicket03();
//        new Thread(sellTicket03).start();
//        new Thread(sellTicket03).start();
//        new Thread(sellTicket03).start();

//        SellTicket04 sellTicket04 = new SellTicket04();
//        new Thread(sellTicket04).start();
//        new Thread(sellTicket04).start();
//        new Thread(sellTicket04).start();

        SellTicket05 sellTicket05 = new SellTicket05();
        new Thread(sellTicket05).start();
        new Thread(sellTicket05).start();
        new Thread(sellTicket05).start();

//        SellTicket06 sellTicket06 = new SellTicket06();
//        new Thread(sellTicket06).start();
//        new Thread(sellTicket06).start();
//        new Thread(sellTicket06).start();
    }
}

//实现接口方式, 使用synchronized实现线程同步
class SellTicket03 implements Runnable {

    private static int ticketNum = 100;//让多个线程共享 ticketNum
    private boolean loop = true;

    //这里的方法就是一个同步方法, 这时锁在this对象
    //也可以在代码块上写synchronized, 同步代码块
    public synchronized void sell() {//同步方法, 在同一时刻, 只能有一个线程来执行sell方法
        if (ticketNum <= 0) {
            System.out.println("窗口 " + Thread.currentThread().getName() +"售票结束...");
            loop = false;
            return;
        }

        //休眠50毫秒, 模拟
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                + " 剩余票数=" + (--ticketNum));

    }
    @Override
    public void run() {
        while (loop) {
            sell();
        }
    }
}

//实现接口方式, 使用synchronized实现线程同步
class SellTicket04 implements Runnable {

    private static int ticketNum = 100;//让多个线程共享 ticketNum
    private boolean loop = true;


    public void sell() {
        synchronized (this) {    //也可以在代码块上写synchronized, 同步代码块, 互斥锁还是在this对象
            if (ticketNum <= 0) {
                System.out.println("窗口 " + Thread.currentThread().getName() +"售票结束...");
                loop = false;
                return;
            }

            //休眠50毫秒, 模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                    + " 剩余票数=" + (--ticketNum));
        }
    }
    @Override
    public void run() {
        while (loop) {
            sell();
        }
    }
}


//实现接口方式, 使用synchronized实现线程同步
class SellTicket05 implements Runnable {

    private static int ticketNum = 100;//让多个线程共享 ticketNum
    private boolean loop = true;
    Object object = new Object();

    public void sell() {
        synchronized (object) {    //在代码块上写synchronized的另外一种方式, 自己创建一个Object对象, 填入括号内, 替换this, 保证是同一个对象就行了
            if (ticketNum <= 0) {
                System.out.println("窗口 " + Thread.currentThread().getName() +"售票结束...");
                loop = false;
                return;
            }

            //休眠50毫秒, 模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                    + " 剩余票数=" + (--ticketNum));
        }
    }
    @Override
    public void run() {
        while (loop) {
            sell();
        }
    }
}


//实现接口方式, 使用synchronized实现线程同步
class SellTicket06 implements Runnable {

    private static int ticketNum = 100;//让多个线程共享 ticketNum
    private boolean loop = true;
    Object object = new Object();

    //同步方法(静态) 的锁为当前类本身
    //public synchronized static void m1() {}的锁是加载SellTicketTicket06.class上的
    //如果在静态方法中, 实现一个同步代码块
    /*
        synchronized (SellTicket06.class){
            System.out.println("m2");
        }
     */
    public synchronized static void m1(){

    }

    public static void m2(){
        synchronized (SellTicket06.class){
            System.out.println("m2");
        }
    }

    public void sell() {
        synchronized (object) {    //也可以在代码块上写synchronized, 同步代码块, 互斥锁还是在this对象
            if (ticketNum <= 0) {
                System.out.println("窗口 " + Thread.currentThread().getName() +"售票结束...");
                loop = false;
                return;
            }

            //休眠50毫秒, 模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                    + " 剩余票数=" + (--ticketNum));
        }
    }
    @Override
    public void run() {
        while (loop) {
            sell();
        }
    }
}


//class SellTicket01 extends Thread {
//
//    private static int ticketNum = 100;//让多个线程共享 ticketNum
//
//    @Override
//    public void run() {
//        while (true) {
//
//            if (ticketNum <= 0) {
//                System.out.println("售票结束...");
//                break;
//            }
//
//            //休眠50毫秒, 模拟
//            try {
//                Thread.sleep(50);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//
//            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
//                    + " 剩余票数=" + (--ticketNum));
//
//        }
//    }
//}
//
//class SellTicket02 implements Runnable {
//
//    private static int ticketNum = 100;//让多个线程共享 ticketNum
//
//    @Override
//    public void run() {
//        while (true) {
//
//            if (ticketNum <= 0) {
//                System.out.println("售票结束...");
//                break;
//            }
//
//            //休眠50毫秒, 模拟
//            try {
//                Thread.sleep(50);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//
//            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
//                    + " 剩余票数=" + (--ticketNum));
//
//        }
//    }
//}